﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lesk;
using System.Linq.Expressions;

namespace Infinity.ExpressionParser
{
	using Tokens;
	using Parsers;
	using System.Text.RegularExpressions;
	using Infinity.ExpressionParser.Comparer;
	using System.Collections;

	static class DemoClass
	{
		public static List<int> Array(int num)
		{
			var lst = new List<int>();
			for (int i = 0; i < num; i++)
			{
				lst.Add(i);
			}
			return lst;
		}

		public static int[] IntArray()
		{
			return Array(5).ToArray();
		}

		public static int[] IntArray(int num)
		{
			return Array(num).ToArray();
		}

		public static double PI()
		{
			return Math.PI;
		}

		public static Dictionary<string, int> Dictionary()
		{
			var dict = new Dictionary<string, int>();
			dict.Add("a", 1);
			dict.Add("b", 2);
			dict.Add("c", 3);
			dict.Add("d", 4);
			dict.Add("e", 5);
			return dict;
		}

		public static int ToInt(object obj)
		{
			return Convert.ToInt32(obj);
		}

		public static List<object> ToList(params object[] objs)
		{
			return new List<object>(objs);
		}

		public static List<object> ToList(HashSet<object> objs)
		{
			return new List<object>(objs);
		}
	}

	class Program
	{
		static void WriteResult(object result)
		{
			if (result is string)
			{
				Console.Write(" \"{0}\";", result);
			}
			else if (result is IEnumerable)
			{
				Console.Write(@" {");
				foreach (var obj in result as IEnumerable)
				{
					WriteResult(obj);
				}
				Console.Write(@"};");
			}
			else
			{
				Console.Write(" {0};", result.ToString());
			}
		}

		static void Main(string[] args)
		{
			ExpressionTreeBuilder builder = new ExpressionTreeBuilder();
			builder.Variables.Add(Expression.Parameter(typeof(double), "x"));
			builder.Variables.Add(Expression.Parameter(typeof(double), "y"));
			builder.Variables.Add(Expression.Parameter(typeof(double), "z"));
			builder.Variables.Add(Expression.Parameter(typeof(List<int>), "a"));

			builder.Functions.Add("sin", typeof(Math).GetMethod("Sin"));
			builder.Functions.Add("cos", typeof(Math).GetMethod("Cos"));
			builder.Functions.Add("abs", typeof(Math).GetMethod("Abs", new[] { typeof(double) }));
			builder.Functions.Add("max", typeof(Math).GetMethod("Max", new[] { typeof(double), typeof(double) }));
			builder.Functions.Add("min", typeof(Math).GetMethod("Min", new[] { typeof(double), typeof(double) }));
			builder.Functions.Add("writeline", typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
			builder.Functions.Add("readkey", typeof(Console).GetMethod("ReadKey", Type.EmptyTypes));
			builder.Functions.Add("array", typeof(DemoClass).GetMethod("Array"));
			builder.Functions.Add("intarray", typeof(DemoClass).GetMethod("IntArray", Type.EmptyTypes));
			builder.Functions.Add("intarray", typeof(DemoClass).GetMethod("IntArray", new[] { typeof(int) }));
			builder.Functions.Add("dict", typeof(DemoClass).GetMethod("Dictionary"));
			builder.Functions.Add("pi", typeof(DemoClass).GetMethod("PI"));
			builder.Functions.Add("int", typeof(DemoClass).GetMethod("ToInt"));
			builder.Functions.Add("list", typeof(DemoClass).GetMethod("ToList", new[] { typeof(object[]) }));
			builder.Functions.Add("tolist", typeof(DemoClass).GetMethod("ToList", new[] { typeof(HashSet<object>) }));

			//var str = "sin(21)+5+(76+50)/(67+4.0)-47657+654-7^2+4.0+2^(2^2*2)";
			//var str = "(-5+sin(21)^sin(2.0) + cos(21)^2.0 + abs(5))";
			//var str = "x:=(-2.0+(-.8)/(654.)+7)^sin(2)";
			//var str = "5 ^ 2 * sin( max( sin( max( 33 , 4 ) ), cos ( min ( 45 , 4 ) ) ) )";
			//var str = "not (false and true or 45 <= (5 - 75)) <=> 75 > 75 => 7 != 45";
			//var str = "writeline(true + 51 * 1.2 + (false + \" Hello World \") + array[array[4 + 5]] + 51.0)";
			//var str = "writeline((intarray[4] + array(10)[4]+intarray[2]+intarray(31)[20])+\"\")";
			//var str = "array(100)[intarray[4]+5+array(11)[10]]+-5 + dict[\"a\"] > 2. + 5 => false";
			//var str = "{1, 2, 3, {4,5,6}} union {\"alma\", \"barack\"} union {10, 11} intersect {11}";
			//var str = "{{1,2,3},2,2,2,3,4} union {1} union {{1}} union {1,2,3} union {{1,2,3},4,5} union {sin(sin(20))} union { 45 <= 5+5 }";

			while (true)
			{
				Console.Write("> ");
				var str = Console.ReadLine();
				try
				{
					var result = builder.Parse(str);
					var resultInvoke = Expression.Lambda(result).Compile().DynamicInvoke(null);
					if (resultInvoke != null)
					{
						Console.Write("result: ");
						WriteResult(resultInvoke);
					}
				}
				catch (Exception ex)
				{
					Console.BackgroundColor = ConsoleColor.Red;
					Console.ForegroundColor = ConsoleColor.Black;
					Console.WriteLine("error: {0}", ex.Message);
					Console.BackgroundColor = ConsoleColor.Black;
					Console.ForegroundColor = ConsoleColor.Gray;
				}
				Console.WriteLine();
			}
		}
	}
}
